package com.zmn.oms.third.zhimi.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.zmn.common.constant.GlobalConsts;
import com.zmn.common.constant.StatusConsts;
import com.zmn.common.utils.date.DateUtil;
import com.zmn.common.utils.string.StringUtil;
import com.zmn.oms.business.interfaces.log.OrderLogBService;
import com.zmn.oms.business.interfaces.third.ZhimiExtendOrderService;
import com.zmn.oms.common.constant.OrderLogConsts;
import com.zmn.oms.common.constant.OrderPostConsts;
import com.zmn.oms.common.constant.OrderStatusConsts;
import com.zmn.oms.common.dto.ResultDTO;
import com.zmn.oms.common.exception.OmsBaseException;
import com.zmn.oms.common.vo.KVDict;
import com.zmn.oms.manager.utils.SpringBeanFactoryUtil;
import com.zmn.oms.model.dto.order.proxy.OrderLogDTO;
import com.zmn.oms.model.entity.dict.ChannelZhimiFault;
import com.zmn.oms.model.entity.dict.ChannelZhimiFaultPart;
import com.zmn.oms.model.entity.log.OrderLog;
import com.zmn.oms.model.entity.order.OrderExtend;
import com.zmn.oms.model.entity.post.OrderPost;
import com.zmn.oms.model.entity.third.ZhimiExtendOrder;
import com.zmn.oms.model.entity.work.OrderWork;
import com.zmn.oms.services.interfaces.dict.ChannelZhimiFaultPartService;
import com.zmn.oms.services.interfaces.dict.ChannelZhimiFaultService;
import com.zmn.oms.services.interfaces.express.OrderPostService;
import com.zmn.oms.services.interfaces.order.OrderExtendService;
import com.zmn.oms.services.interfaces.work.OrderWorkService;
import com.zmn.oms.third.base.dto.api.ApiInvokResult;
import com.zmn.oms.third.zhimi.ZhimiApiInvoker;
import com.zmn.oms.third.zhimi.ZhimiConsts;
import com.zmn.oms.third.zhimi.api.*;
import com.zmn.oms.third.zhimi.dto.CheckResultDTO;
import com.zmn.oms.third.zhimi.dto.SaveBuyDateResulstDTO;
import com.zmn.oms.third.zhimi.entity.ZhimiOrderExtend;
import com.zmn.oms.third.zhimi.service.ZhimiOrderExtendService;
import com.zmn.oms.third.zhimi.service.ZhimiOrderNotifyService;
import com.zmn.oms.zmn.aop.OrderWorkLogUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author sunlife
 * @date:2020/4/27 10:51 上午
 * description:
 */
@Slf4j
@Service
public class ZhimiOrderExtendServiceImpl implements ZhimiOrderExtendService {

    @Autowired
    private OrderWorkService orderWorkService;
    @Autowired
    private OrderLogBService orderLogBService;
    @Autowired
    private ZhimiExtendOrderService zhimiExtendOrderService;
    @Autowired
    private ChannelZhimiFaultService channelZhimiFaultService;
    @Autowired
    private ChannelZhimiFaultPartService channelZhimiFaultPartService;
    @Autowired
    private OrderExtendService orderExtendService;
    @Autowired
    private OrderPostService orderPostService;
    // 不能使用自动注入，否则会出现相互依赖
    private ZhimiOrderNotifyService zhimiOrderNotifyService;

    @Override
    public void saveZhimiOrderExtend(ZhimiOrderExtend zhimiOrderExtend) throws OmsBaseException {
        ZhimiExtendOrder model = new ZhimiExtendOrder();
        model.setOrderId(zhimiOrderExtend.getOrderId());
        model.setOuterId(zhimiOrderExtend.getOuterId());
        model.setOriginalServiceType(zhimiOrderExtend.getOriginalServiceType());
        model.setServiceType(zhimiOrderExtend.getServiceType());
        model.setAcFlag(zhimiOrderExtend.getAcFlag());
        model.setWarranty(zhimiOrderExtend.getWarranty());

        zhimiExtendOrderService.save(model);
    }

    @Override
    public ZhimiOrderExtend findZhimiOrderExtendByOrderId(Long orderId) {
        return findZhimiOrderExtend(orderId, true);
    }

    /**
     * 判断是否用料
     * @return
     */
    @Override
    public int useParts(List<ZhimiOrderExtend.Fault> faults, String thirdModelCode) {
        if (CollectionUtils.isEmpty(faults) || StringUtil.isBlank(thirdModelCode)) {
            return ZhimiConsts.NO;
        }

        List<String> faultCodeList = faults.stream().map(item -> item.getCode()).collect(Collectors.toList());
        int num = channelZhimiFaultPartService.countByFaultCodeLv3List(faultCodeList, thirdModelCode);

        return num > 0 ? ZhimiConsts.YES : ZhimiConsts.NO;
    }

    /**
     * 校验sn号是否有效，如果失败，返回相关信息
     * @param orderId
     * @param sn
     * @param thirdModelCode 三级机型编码，sn传"800000"时必填，其他传null即可
     * @return
     */
    @Override
    public CheckResultDTO checkSNCode(Long orderId, String sn, String thirdModelCode) {
        if (orderId == null) {
            return CheckResultDTO.fail("订单号不能为空");
        }
        if (StringUtil.isBlank(sn)) {
            return CheckResultDTO.fail("SN码不能为空");
        }

        // 忽略SN校验标识
        boolean isGlobalSNCode = ZhimiConsts.SN_GLOBAL.equals(sn);

        if (isGlobalSNCode) {
            if (StringUtil.isBlank(thirdModelCode)) {
                return CheckResultDTO.fail("SN码使用\"800000\"时必需指定三级机型");
            }
            ZhimiConsts.MainPartCode mainPartCode = ZhimiConsts.getMainPartCode(thirdModelCode);
            if (mainPartCode == null) {
                return CheckResultDTO.fail("请选择正确的三级机型");
            }
        }

        ZhimiOrderExtend dbZhimiOrderExtend = findZhimiOrderExtend(orderId, false);
        if (dbZhimiOrderExtend == null) {
            return CheckResultDTO.fail("订单不存在");
        }

        if (StringUtil.isNotBlank(dbZhimiOrderExtend.getNewSn()) && sn.equals(dbZhimiOrderExtend.getNewSn())) {
            return CheckResultDTO.fail("旧机SN码不能与新机SN码相同");
        }

        ZhimiSNCheckResp zhimiSNCheckResp = null;
        // 忽略SN校验，使用了“800000”作为SN
        if (isGlobalSNCode) {
            // 安装单，不允许使用“800000”作为SN
            Integer zhimiServiceType = Optional
                    .ofNullable(dbZhimiOrderExtend.getOriginalServiceType())
                    .orElse(dbZhimiOrderExtend.getServiceType());
            if (ZhimiConsts.SERVICE_TYPE_INSTALL == zhimiServiceType.intValue()) {
                return CheckResultDTO.fail("该订单不允许使用“800000”，请填写正确的SN码");
            }

            // 忽略SN校验
            zhimiSNCheckResp = new ZhimiSNCheckResp();
            zhimiSNCheckResp.setSn(sn);
            zhimiSNCheckResp.setThirdmodel(thirdModelCode);
        }
        else {
            ApiInvokResult<ZhimiSNCheckResp> result = ZhimiApiInvoker.checkSN(dbZhimiOrderExtend.getOuterId(), sn);
            if (!result.isSuccess()) {
                String msg = Optional.ofNullable(result.getMsg()).orElse("");
                log.info("【{}】SN码校验失败：{}。orderId=[{}], SN=[{}]", ZhimiConsts.CHANNEL_NAME, msg, orderId, sn);
                return CheckResultDTO.fail("SN校验失败："+ msg.replace("WMS接口返回错误提示：", ""));
            }
            zhimiSNCheckResp = result.getData();
            if (StringUtil.isBlank(zhimiSNCheckResp.getThirdmodel())) {
                return CheckResultDTO.fail("智米未提供该SN对应的三级机型编码，请联系业务人员处理");
            }
        }

        // 保存SN校验信息
        ZhimiExtendOrder zhimiExtendOrder = updateSNCheckInfo(orderId, zhimiSNCheckResp);

        if (Objects.equals(ZhimiConsts.WARRANTY_IN, zhimiExtendOrder.getWarranty())) {
            // 正确，且在保修期的SN码
            return CheckResultDTO.success();
        }
        else {
            // 不在保修期的SN码
            return CheckResultDTO.success(false);
        }
    }

    /**
     * 校验sn号是否有效，如果失败，返回相关信息
     * @param orderId
     * @param newSn
     * @return
     */
    @Override
    public CheckResultDTO checkNewSNCode(Long orderId, String newSn) {
        if (orderId == null) {
            return CheckResultDTO.fail("订单号不能为空");
        }
        if (StringUtil.isBlank(newSn)) {
            return CheckResultDTO.fail("SN码不能为空");
        }
        if (ZhimiConsts.SN_GLOBAL.equals(newSn)) {
            return CheckResultDTO.fail("SN码无效");
        }

        ZhimiOrderExtend zhimiOrderExtend = findZhimiOrderExtend(orderId, false);
        if (zhimiOrderExtend == null) {
            return CheckResultDTO.fail("订单不存在");
        }

        // 换机单才有新SN
        Integer zhimiServiceType = Optional
                .ofNullable(zhimiOrderExtend.getOriginalServiceType())
                .orElse(zhimiOrderExtend.getServiceType());
        if (Objects.equals(ZhimiConsts.SERVICE_TYPE_EXCHANGE, zhimiServiceType)
                || Objects.equals(ZhimiConsts.SERVICE_TYPE_REPAIR, zhimiServiceType)) {
        }
        else {
            return CheckResultDTO.fail("仅'换机单/维修单'支持新SN校验");
        }

        if (Objects.equals(newSn, zhimiOrderExtend.getSn())) {
            return CheckResultDTO.fail("新机SN码不能与旧机SN码相同");
        }

        ZhimiSNCheckResp zhimiNewSNCheckResp = null;
        {
            ApiInvokResult<ZhimiSNCheckResp> newSNResult = ZhimiApiInvoker.checkSN(zhimiOrderExtend.getOuterId(), newSn);
            if (!newSNResult.isSuccess()) {
                String msg = Optional.ofNullable(newSNResult.getMsg()).orElse("");
                log.info("【{}】新机SN码校验失败：{}。orderId=[{}], SN=[{}]", ZhimiConsts.CHANNEL_NAME, msg, orderId, newSn);
                return CheckResultDTO.fail("新机SN校验失败："+ msg.replace("WMS接口返回错误提示：", ""));
            }
            else {
                zhimiNewSNCheckResp = newSNResult.getData();
            }
        }

        // 保存SN校验信息
        updateNewSNCheckInfo(zhimiOrderExtend, zhimiNewSNCheckResp);

        return CheckResultDTO.success();
    }

    /**
     * 获取可选择的故障列表
     * @param orderId
     * @return
     */
    @Override
    public List<KVDict<String>> getFaultList(Long orderId) {
        ZhimiOrderExtend zhimiOrderExtend = findZhimiOrderExtend(orderId, true);

        // 走以换代修的维修单，不提供可选故障列表
        if (zhimiOrderExtend != null
                && Objects.equals(ZhimiConsts.SERVICE_TYPE_REPAIR, zhimiOrderExtend.getServiceType())
                && Objects.equals(GlobalConsts.YES, zhimiOrderExtend.getReplaceOnly())) {
            return new LinkedList<>();
        }

        // 构造已选故障项筛选器
        Map<String, ZhimiOrderExtend.Fault> selectedFaultsFilter = new HashMap<>();
        if (!CollectionUtils.isEmpty(zhimiOrderExtend.getFaults())) {
            zhimiOrderExtend.getFaults().forEach(item -> {
                selectedFaultsFilter.put(item.getCode(), item);
            });
        }

        // 组装可选故障项
        List<KVDict<String>> faultList = new LinkedList<>();
        List<ChannelZhimiFault> faults = channelZhimiFaultService.listByThirdModelCode(zhimiOrderExtend.getThirdModelCode());
        for (ChannelZhimiFault item : faults) {
            KVDict<String> dict = new KVDict();
            dict.setValue(item.getFaultCodeLv3());
            dict.setText(item.getFaultNameLv3());
            dict.setPid(item.getFaultCodeLv2());
            dict.setPidText(item.getFaultNameLv2());
            dict.setType(GlobalConsts.YES);
            dict.setSelected(selectedFaultsFilter.get(item.getFaultCodeLv3()) != null);
            faultList.add(dict);
        }
        // 非用料维修故障项
        List<ChannelZhimiFault> unusePartFaults = ZhimiConsts.getUnusePartFaults();
        for (ChannelZhimiFault item : unusePartFaults) {
            KVDict<String> dict = new KVDict();
            dict.setValue(item.getFaultCodeLv3());
            dict.setText(item.getFaultNameLv3());
            dict.setPid(item.getFaultCodeLv2());
            dict.setPidText(item.getFaultNameLv2());
            dict.setType(GlobalConsts.NO);
            dict.setSelected(selectedFaultsFilter.get(item.getFaultCodeLv3()) != null);
            faultList.add(dict);
        }

        return faultList;
    }

    /**
     * 保存故障信息
     * @param zhimiOrderExtend
     *  zhimiOrderExtend实列的 orderId, faults 两个属性不能为空
     */
    @Override
    public ResultDTO saveOrderFaults(ZhimiOrderExtend zhimiOrderExtend) {
        Long orderId = zhimiOrderExtend.getOrderId();
        if (orderId == null) {
            return ResultDTO.fail("订单ID不能为空");
        }
        List<ZhimiOrderExtend.Fault> faults = zhimiOrderExtend.getFaults();
        if (CollectionUtils.isEmpty(faults)) {
            return ResultDTO.fail("故障信息不能为空");
        }
        ZhimiOrderExtend dbZhimiOrderExtend = findZhimiOrderExtend(orderId, true);
        if (dbZhimiOrderExtend == null) {
            return ResultDTO.fail("订单不存在");
        }
        if (!CollectionUtils.isEmpty(dbZhimiOrderExtend.getParts())) {
            return ResultDTO.fail("订单已申请了配件");
        }

        int useParts = useParts(faults, dbZhimiOrderExtend.getThirdModelCode());
        if (ZhimiConsts.YES == useParts) {
            Map<String, ChannelZhimiFault> unusePartFaultFilter = new HashMap<>(20);
            ZhimiConsts.getUnusePartFaults().forEach(item -> {
                unusePartFaultFilter.put(item.getFaultCodeLv3(), item);
            });
            for (ZhimiOrderExtend.Fault item : faults) {
               if (unusePartFaultFilter.get(item.getCode()) != null) {
                   return ResultDTO.fail("不能同时选择【用料故障】和【非用料故障】");
               }
            }
        }

        ZhimiOrderExtend updateModel = new ZhimiOrderExtend();
        updateModel.setOrderId(orderId);
        updateModel.setFaults(zhimiOrderExtend.getFaults());
        updateModel.setUseParts(useParts);

        updateExtendData(updateModel);

        // 记录日志
        try {
            OrderLogDTO orderLogDTO = new OrderLogDTO();
            orderLogDTO.setOrderId(orderId);
            orderLogDTO.setWorkId(orderId);

            StringBuilder sb = new StringBuilder("师傅操作：添加故障信息：");
            zhimiOrderExtend.getFaults().stream().forEach(item -> {
                sb.append(item.getName()).append("，");
            });
            orderLogDTO.setOperatorLogRemark(sb.toString());

            saveOrderLog(orderId, orderLogDTO);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return ResultDTO.success();
    }

    /**
     * 获取可选择的配件列表
     * @param orderId
     * @return
     */
    @Override
    public ZhimiOrderExtend getPartList(Long orderId) {
        ZhimiOrderExtend dbZhimiOrderExtend = findZhimiOrderExtend(orderId, true);

        // 组装可选配件列表
        List<ZhimiOrderExtend.Part> partlist = new LinkedList<>();

        String thirdModelCode = dbZhimiOrderExtend.getThirdModelCode();
        Integer serviceType = dbZhimiOrderExtend.getServiceType();

        do {
            // 非 换机单、维修单，不可选择配件物料
            if (!Objects.equals(ZhimiConsts.SERVICE_TYPE_EXCHANGE, serviceType)
                    && !Objects.equals(ZhimiConsts.SERVICE_TYPE_REPAIR, serviceType)) {
                break;
            }

            // 维修单
            if (Objects.equals(ZhimiConsts.SERVICE_TYPE_REPAIR, serviceType)) {
                if (Objects.equals(GlobalConsts.YES, dbZhimiOrderExtend.getReplaceOnly())) {
                    // 以换代修订单，不提供可选物料列表
                    break;
                }
                Integer useParts = Optional
                        .ofNullable(dbZhimiOrderExtend.getUseParts())
                        .orElse(useParts(dbZhimiOrderExtend.getFaults(), thirdModelCode));
                if (Objects.equals(ZhimiConsts.NO, useParts)) {
                    // 所选故障不需要配件，不提供可选配件
                    break;
                }

                // 过滤已选故障项对应使用的配件，作为可选配件
                Map<String, String> filter = new HashMap<>();
                filter.put("E95TOS1901202S", "E95TOS1901202S"); // 怡和版/爱创版-机头不能选（爱创与怡和共用一个机头配件）
                filter.put("E5020121220002S", "E5020121220002S"); // 西马版-机头不能选
                if (!CollectionUtils.isEmpty(dbZhimiOrderExtend.getParts())) {
                    // 已申请配件不能再次申请
                    dbZhimiOrderExtend.getParts().forEach(item -> {
                        filter.put(item.getCode(), item.getCode());
                    });
                }
                List<ZhimiOrderExtend.Fault> faults = dbZhimiOrderExtend.getFaults();
                if (!CollectionUtils.isEmpty(faults)) {
                    for (ZhimiOrderExtend.Fault selected : faults) {
                        List<ChannelZhimiFaultPart> faultParts = channelZhimiFaultPartService
                                .listByFaultCodeLv3(selected.getCode(), thirdModelCode);
                        for (ChannelZhimiFaultPart item : faultParts) {
                            String partCode = item.getPartCode().trim();
                            if (filter.get(partCode) != null) {
                                // 去除重复配件
                                continue;
                            }
                            filter.put(partCode, partCode);

                            ZhimiOrderExtend.Part part = new ZhimiOrderExtend.Part();
                            part.setCode(partCode);
                            part.setName(item.getPartName());

                            partlist.add(part);
                        }
                    }
                }
                break;
            }

            // 换机单且是以换代修订单，只提供机头物料
            if (Objects.equals(GlobalConsts.YES, dbZhimiOrderExtend.getReplaceOnly())) {
                ChannelZhimiFaultPart headPart =
                        channelZhimiFaultPartService.findByPartCode(dbZhimiOrderExtend.getHeadPartCode(), thirdModelCode);
                if (headPart != null) {
                    ZhimiOrderExtend.Part part = new ZhimiOrderExtend.Part();
                    part.setCode(headPart.getPartCode());
                    part.setName(headPart.getPartName());
                    partlist.add(part);
                }
                break;
            }
        } while (false);

        ZhimiOrderExtend zhimiOrderExtend = new ZhimiOrderExtend();
        zhimiOrderExtend.setOrderId(orderId);
        zhimiOrderExtend.setParts(partlist);
        zhimiOrderExtend.setPostAddress(dbZhimiOrderExtend.getPostAddress());

        return zhimiOrderExtend;
    }

    /**
     * 保存配件信息
     * @param zhimiOrderExtend
     *  zhimiOrderExtend实列的 orderId, parts, postAddress 三个属性不能为空
     */
    @Override
    public ResultDTO saveOrderParts(ZhimiOrderExtend zhimiOrderExtend) {
        Long orderId = zhimiOrderExtend.getOrderId();
        List<ZhimiOrderExtend.Part> parts = zhimiOrderExtend.getParts();
        ZhimiOrderExtend.PostAddress postAddress = zhimiOrderExtend.getPostAddress();

        if (orderId == null) {
            return ResultDTO.fail("订单ID不能为空");
        }
        if (CollectionUtils.isEmpty(parts)) {
            return ResultDTO.fail("配件信息不能为空");
        }
        if (parts.size() > 3) {
            return ResultDTO.fail("不允许申请超过3个配件");
        }
        if (postAddress == null || StringUtil.isBlank(postAddress.getName())
                || StringUtil.isBlank(postAddress.getPhone()) || StringUtil.isBlank(postAddress.getAddress())) {
            return ResultDTO.fail("收货信息不完整");
        }

        ZhimiOrderExtend dbZhimiOrderExtend = findZhimiOrderExtend(orderId, true);
        if (zhimiOrderExtend == null) {
            return ResultDTO.fail("订单不存在");
        }
        if (!CollectionUtils.isEmpty(dbZhimiOrderExtend.getParts())) {
            return ResultDTO.fail("该订单已申请了配件，不能再次申请");
        }
        List<ZhimiOrderExtend.Fault> faults = dbZhimiOrderExtend.getFaults();
        if (CollectionUtils.isEmpty(faults)) {
            return ResultDTO.fail("故障信息不能为空");
        }

        String applyTime = DateUtil.dateFormatToString(new Date(), DateUtil.FORMAT_DEFAULT);

        // 申请配件
        ApiInvokResult result = null;
        {
            ZhimiApplyPartsReq applyPartsReq = new ZhimiApplyPartsReq();
            applyPartsReq.setName(dbZhimiOrderExtend.getOuterId());
            applyPartsReq.setType(2);   // 类型固定填2
            applyPartsReq.setStationcode(ZhimiConsts.APP_ID);
            applyPartsReq.setStockcode(ZhimiConsts.STORE_ID);
            applyPartsReq.setSubmit_time(applyTime);
            applyPartsReq.setRecipient(postAddress.getName());
            applyPartsReq.setAddress(postAddress.getAddress());
            applyPartsReq.setPhonenumber(postAddress.getPhone());


            List<ZhimiApplyPartsReq.Part> applyParts = new LinkedList<>();
            for (ZhimiOrderExtend.Part item : parts) {
                // 只允许申请一个配件
                item.setNumber(1);

                ZhimiApplyPartsReq.Part applyPart = new ZhimiApplyPartsReq.Part();
                applyPart.setMaterialcode(item.getCode());
                applyPart.setQty(item.getNumber());
                applyPart.setSn(dbZhimiOrderExtend.getSn());
                applyParts.add(applyPart);
            }
            applyPartsReq.setDatalines(applyParts);

            List<ZhimiApplyPartsReq.Fault> faultlines = new LinkedList<>();
            for (ZhimiOrderExtend.Fault item : faults) {
                ZhimiApplyPartsReq.Fault faultObj = new ZhimiApplyPartsReq.Fault();
                faultObj.setFaultcode(item.getCode());
                faultObj.setFaultname(item.getName());
                faultlines.add(faultObj);
            }
            applyPartsReq.setFaultlines(faultlines);

            result = ZhimiApiInvoker.partApply(JSON.toJSONString(applyPartsReq));
        }

        // 保存配件信息
        if (result.isSuccess()) {   // 保存配件信息
            ZhimiOrderExtend updateModel = new ZhimiOrderExtend();
            updateModel.setOrderId(orderId);
            updateModel.setPostAddress(postAddress);

            List<ZhimiOrderExtend.Part> totalParts = new LinkedList<>();
            if (!CollectionUtils.isEmpty(dbZhimiOrderExtend.getParts())) {
                totalParts.addAll(dbZhimiOrderExtend.getParts());
            }

            for (ZhimiOrderExtend.Part item : parts) {
                item.setApplyTime(applyTime);
                totalParts.add(item);
            }
            updateModel.setParts(totalParts);
            updateModel.setExpressWaiting(GlobalConsts.YES);

            updateExtendData(updateModel);
        }

        // 记录日志
        try {
            OrderLogDTO orderLogDTO = new OrderLogDTO();
            orderLogDTO.setOrderId(orderId);
            orderLogDTO.setWorkId(orderId);

            StringBuilder sb = new StringBuilder("师傅操作：");
            if (result.isSuccess()) {
                sb.append("申请配件：");
                parts.stream().forEach(item -> {
                    sb.append(item.getName()).append("，");
                });
            }
            else {
                sb.append("申请配件失败：").append(result.getMsg());
            }
            sb.append(" 收件人：").append(postAddress.getName())
                    .append("-").append(postAddress.getPhone())
                    .append("，收件地址：").append(postAddress.getAddress()).append("；");
            orderLogDTO.setOperatorLogRemark(sb.toString());

            saveOrderLog(orderId, orderLogDTO);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return result.isSuccess() ? ResultDTO.success() : ResultDTO.fail("申请配件失败："+ result.getMsg());
    }

    /**
     * 获取已申请的配件列表
     * @return
     */
    @Override
    public List<ZhimiOrderExtend.Part> getAppliedPartList(Long orderId) {
        ZhimiOrderExtend zhimiOrderExtend = findZhimiOrderExtend(orderId, true);

        List<ZhimiOrderExtend.Part> appliedParts = zhimiOrderExtend.getParts();
        if (appliedParts == null) {
            appliedParts = new LinkedList<>();
        }

        return appliedParts;
    }

    /**
     * 获取已申请的配件的邮寄信息
     * @return
     */
    @Override
    public ZhimiExpressResp pullAppliedPartExpress(ZhimiOrderExtend zhimiOrderExtend) {
        ApiInvokResult<ZhimiExpressResp> result = ZhimiApiInvoker.queryPartExpress(zhimiOrderExtend.getOuterId());
        if (!result.isSuccess()) {
            return null;
        }

        ZhimiExpressResp zhimiExpressResp = result.getData();
        Long orderId = zhimiOrderExtend.getOrderId();
        ZhimiOrderExtend dbZhimiOrderExtend = findZhimiOrderExtend(orderId, true);

        {//  更新已申请配件的物流信息
            List<ZhimiOrderExtend.Part> appliedParts = dbZhimiOrderExtend.getParts();
            if (!CollectionUtils.isEmpty(appliedParts)) {
                for (ZhimiOrderExtend.Part item : appliedParts) {
                    if (StringUtil.isBlank(item.getExpressCode())) {
                        item.setExpressCode(zhimiExpressResp.getTracking_num());
                        item.setExpressCompany(zhimiExpressResp.getDelivery_company());
                        item.setExpressTime(zhimiExpressResp.getDelivery_date());
                    }
                }

                ZhimiOrderExtend updateModel = new ZhimiOrderExtend();
                updateModel.setOrderId(orderId);
                updateModel.setParts(appliedParts);
                updateModel.setExpressWaiting(GlobalConsts.NO);
                updateExtendData(updateModel);
            }
        }

        try {// 快递信息同步给OMS
            OrderPost orderPost = new OrderPost();
            orderPost.setOrderId(orderId);
            orderPost.setItemType(OrderPostConsts.EXPRESS_ITEMTYPE_NEW_FITTINGS);
            orderPost.setSourceType(OrderPostConsts.SOURCE_TYPE_CHANNEL);
            orderPost.setModifiable(GlobalConsts.NO);
            // 快递单号，快递公司
            orderPost.setExpressCode(zhimiExpressResp.getTracking_num());
            orderPost.setExpressCompanyCode(zhimiExpressResp.getDelivery_company());
            // 收货地址，收货人
            ZhimiOrderExtend.PostAddress postAddress = dbZhimiOrderExtend.getPostAddress();
            if (postAddress != null) {
                orderPost.setReceiveAddress(postAddress.getAddress());
                orderPost.setReceiver(postAddress.getName());
            }

            orderPostService.insertOrderPost(orderPost);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return zhimiExpressResp;
    }

    /**
     * 保存勘测结果，检测结果，换机结果，退机结果
     * @param zhimiOrderExtend
     * @return
     */
    public ResultDTO saveZhimiOrderExtendLocalInfo(ZhimiOrderExtend zhimiOrderExtend) {
        Long orderId = zhimiOrderExtend.getOrderId();
        if (orderId == null) {
            return ResultDTO.fail("订单ID不能为空");
        }
        if (zhimiOrderExtend.getDetection() == null && zhimiOrderExtend.getExchange() == null
                && zhimiOrderExtend.getRetund() == null && zhimiOrderExtend.getSurvey() == null) {
            return ResultDTO.fail("参数不全");
        }

        ZhimiOrderExtend model = new ZhimiOrderExtend();
        model.setOrderId(orderId);
        model.setDetection(zhimiOrderExtend.getDetection());
        model.setExchange(zhimiOrderExtend.getExchange());
        model.setRetund(zhimiOrderExtend.getRetund());
        model.setSurvey(zhimiOrderExtend.getSurvey());

        updateExtendData(model);

        // 记录日志
        try {
            OrderLogDTO orderLogDTO = new OrderLogDTO();
            orderLogDTO.setOrderId(orderId);
            orderLogDTO.setWorkId(orderId);


            { // 拼装日志内容
                StringBuilder operatorLog = new StringBuilder("师傅操作：");

                ZhimiOrderExtend.Detection detection = zhimiOrderExtend.getDetection();
                if (detection != null) {
                    String type = Objects.equals(ZhimiConsts.DETECTION_DOA, detection.getType()) ? "DOA"
                            : Objects.equals(ZhimiConsts.DETECTION_DAP, detection.getType()) ? "DAP"
                            : String.format("未知结果：%d", detection.getType());
                    operatorLog.append("保存检测结果：").append(type)
                            .append("，备注：").append(detection)
                            .append("；");
                }
                ZhimiOrderExtend.Exchange exchange = zhimiOrderExtend.getExchange();
                if (exchange != null) {
                    String type = Objects.equals(ZhimiConsts.EXCHANGE_DOA, exchange.getType()) ? "DOA"
                            : Objects.equals(ZhimiConsts.EXCHANGE_DAP, exchange.getType()) ? "DAP"
                            : Objects.equals(ZhimiConsts.EXCHANGE_OTHER, exchange.getType()) ? "多维换机"
                            : Objects.equals(ZhimiConsts.NO, exchange.getType()) ? "不予换机"
                            : String.format("未知结果：%d", exchange.getType());
                    operatorLog.append("保存换机结果：").append(type).append("；");
                }
                ZhimiOrderExtend.Retund retund = zhimiOrderExtend.getRetund();
                if (retund != null) {
                    String type = Objects.equals(ZhimiConsts.RETURN_FORCE, retund.getType()) ? "7天无理由退货"
                            : Objects.equals(ZhimiConsts.RETURN_BROKEN, retund.getType()) ? "质量问题"
                            : Objects.equals(ZhimiConsts.RETURN_POST_WRONG, retund.getType()) ? "发错货退货"
                            : Objects.equals(ZhimiConsts.NO, retund.getType()) ? "不予退货"
                            : String.format("未知结果：%d", retund.getType());
                    operatorLog.append("保存退货结果：").append(type).append("；");
                }
                ZhimiOrderExtend.Survey survey = zhimiOrderExtend.getSurvey();
                if (survey != null) {
                    String state = Objects.equals(ZhimiConsts.YES, survey.getState()) ? "可以安装"
                            : (Objects.equals(ZhimiConsts.NO, survey.getState()) ? "无法安装"
                            : String.format("未知结果：%d", survey.getState()));
                    operatorLog.append("保存勘测结果：").append(state)
                            .append("，备注：").append(survey.getRemark())
                            .append("；");
                }

                orderLogDTO.setOperatorLogRemark(operatorLog.toString());
            }

            saveOrderLog(orderId, orderLogDTO);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return ResultDTO.success();
    }

    /**
     * 保存购机日期，当订单是保外单时调用有效。
     *  该方法用于人工修正订单是否在保修期内，当订单不在保修期时，通过传入发票的购机日期，重新判断产品是否在保修期
     * @param zhimiOrderExtend
     *  zhimiOrderExtend实列的 orderId, buyDate 两个属性不能为空
     */
    @Override
    public ResultDTO<SaveBuyDateResulstDTO> saveBuyDate(ZhimiOrderExtend zhimiOrderExtend) {
        Long orderId = zhimiOrderExtend.getOrderId();
        String buyDateStr = zhimiOrderExtend.getBuyDate();

        if (orderId == null) {
            return ResultDTO.fail("订单ID不能为空");
        }
        if (StringUtil.isBlank(buyDateStr)) {
            return ResultDTO.fail("购机日期不能为空");
        }

        Date buyDate = DateUtil.parse(buyDateStr, DateUtil.FORMAT_DATE);
        if (buyDate == null) {
            buyDate = DateUtil.parse(buyDateStr, DateUtil.FORMAT_DATE2);
        }
        if (buyDate == null) {
            return ResultDTO.fail("购机日期填写有误");
        }

        ZhimiOrderExtend dbZhimiOrderExtend = findZhimiOrderExtend(orderId, false);
        if (dbZhimiOrderExtend == null) {
            return ResultDTO.fail("订单不存在");
        }
        if (StringUtil.isBlank(dbZhimiOrderExtend.getSn())) {
            return ResultDTO.fail("请先填写SN");
        }

        StringBuilder operatorLog = new StringBuilder();
        operatorLog.append("师傅操作：修改购机日期为：").append(buyDateStr);

        ZhimiExtendOrder updateModel = new ZhimiExtendOrder();
        updateModel.setOrderId(orderId);
        updateModel.setBuyDate(DateUtil.toString(buyDate, DateUtil.FORMAT_DATE));

        fillWarrantyInfo(updateModel, dbZhimiOrderExtend, operatorLog);

        zhimiExtendOrderService.updateByKey(updateModel);

        // 记录日志
        try {
            OrderLogDTO orderLogDTO = new OrderLogDTO();
            orderLogDTO.setOrderId(orderId);
            orderLogDTO.setWorkId(orderId);

            operatorLog.append("；");
            orderLogDTO.setOperatorLogRemark(operatorLog.toString());

            saveOrderLog(orderId, orderLogDTO);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        SaveBuyDateResulstDTO saveBuyDateResulstDTO = new SaveBuyDateResulstDTO();
        saveBuyDateResulstDTO.setReplaceOnly(updateModel.getReplaceOnly());
        saveBuyDateResulstDTO.setWarranty(updateModel.getWarranty());
        do {
            // 出保订单需联系智米重新下保外订单
            if (Objects.equals(ZhimiConsts.WARRANTY_OUT, saveBuyDateResulstDTO.getWarranty() )) {
                saveBuyDateResulstDTO.setStatus(StatusConsts.STATUS_ERROR);
                saveBuyDateResulstDTO.setMessage("该订单已出保");
                break;
            }

            Integer currServiceType = Optional.ofNullable(dbZhimiOrderExtend.getServiceType())
                    .orElse(dbZhimiOrderExtend.getOriginalServiceType());
            // 如果是维修订单，且是以换代修订单，需联系智米重新下换机订单
            if (Objects.equals(GlobalConsts.YES, saveBuyDateResulstDTO.getReplaceOnly())
                    && Objects.equals(ZhimiConsts.SERVICE_TYPE_REPAIR, currServiceType)) {
                saveBuyDateResulstDTO.setStatus(StatusConsts.STATUS_ERROR);
                saveBuyDateResulstDTO.setMessage(
                        Optional.ofNullable(ZhimiConsts.getMainPartCode(dbZhimiOrderExtend.getThirdModelCode()))
                                // 针对支持维修的机型，一年内使用以换代修，超过一年，不使用以换代修
                                .map(e -> e.isReplaceOnly() ? null : "该机器购买一年以内，请联系言而有信平台做【换机】处理")
                                .orElse("该机型不支持【维修】，请联系言而有信平台做【换机】处理")
                );
                break;
            }

            saveBuyDateResulstDTO.setStatus(StatusConsts.STATUS_SUCCESS);
        } while (false);

        return ResultDTO.success(saveBuyDateResulstDTO);
    }

    /**
     * 保存返厂物流信息
     * @param zhimiOrderExtend zhimiOrderExtend实列的 orderId, returnFactoryExpress 两个属性不能为空
     * @return
     */
    @Override
    public ResultDTO saveReturnFactoryExpress(ZhimiOrderExtend zhimiOrderExtend) {
        Long orderId = zhimiOrderExtend.getOrderId();
        if (orderId == null) {
            return ResultDTO.fail("订单ID不能为空");
        }
        ZhimiOrderExtend.ReturnFactoryExpress returnFactoryExpress = zhimiOrderExtend.getReturnFactoryExpress();
        if (returnFactoryExpress == null || StringUtil.isBlank(returnFactoryExpress.getExpressCode())
                || StringUtil.isBlank(returnFactoryExpress.getExpressCompanyCode())
                || StringUtil.isBlank(returnFactoryExpress.getExpressTime())) {
            return ResultDTO.fail("物流信息不完整");
        }

        ZhimiConsts.ExpressCompany expressCompany =
                ZhimiConsts.getExpressCompanyByCode(returnFactoryExpress.getExpressCompanyCode());
        if (expressCompany == null) {
            return ResultDTO.fail("物流公司无法识别");
        }

        ZhimiOrderExtend model = new ZhimiOrderExtend();
        model.setOrderId(orderId);

        returnFactoryExpress.setExpressCompany(expressCompany.getName());
        model.setReturnFactoryExpress(returnFactoryExpress);

        updateExtendData(model);

        // 记录日志
        try {
            OrderLogDTO orderLogDTO = new OrderLogDTO();
            orderLogDTO.setOrderId(orderId);
            orderLogDTO.setWorkId(orderId);

            StringBuilder operatorLog = new StringBuilder();
            operatorLog.append("师傅操作：保存旧件返厂信息：")
                    .append("快递公司：").append(returnFactoryExpress.getExpressCompany())
                    .append("，快递单号：").append(returnFactoryExpress.getExpressCode())
                    .append("，寄件时间：").append(returnFactoryExpress.getExpressTime())
                    .append("；");
            orderLogDTO.setOperatorLogRemark(operatorLog.toString());

            saveOrderLog(orderId, orderLogDTO);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        // 快递信息同步给OMS
        try {
            OrderPost orderPost = new OrderPost();
            orderPost.setOrderId(orderId);
            orderPost.setItemType(OrderPostConsts.EXPRESS_ITEMTYPE_OLD_FITTINGS);
            orderPost.setSourceType(OrderPostConsts.SOURCE_TYPE_PLATFORM);
            orderPost.setModifiable(GlobalConsts.YES);
            // 快递单号，快递公司
            orderPost.setExpressCode(returnFactoryExpress.getExpressCode());
            orderPost.setExpressCompanyCode(expressCompany.getCompanyCode());

            orderPostService.insertOrderPost(orderPost);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return ResultDTO.success();
    }

    /**
     * 修改智米订单服务类型
     * @param orderId
     * @param serviceType
     * @return
     */
    @Override
    public ResultDTO updateServiceType(Long orderId, Integer serviceType) {
        ZhimiOrderExtend dbZhimiOrderExtend = findZhimiOrderExtend(orderId, false);
        if (!Objects.equals(serviceType, dbZhimiOrderExtend.getServiceType())) {
            ZhimiExtendOrder updateModel = new ZhimiExtendOrder();
            updateModel.setOrderId(orderId);
            updateModel.setServiceType(serviceType);

            zhimiExtendOrderService.updateServiceTypeByKey(updateModel);

            // 记录日志
            try {
                OrderLogDTO orderLogDTO = new OrderLogDTO();
                orderLogDTO.setOrderId(orderId);
                orderLogDTO.setWorkId(orderId);

                String errorTip = String.format("变更智米订单服务类型：%s -> %s，清空所有智米数据",
                        ZhimiConsts.getServiceTypeName(dbZhimiOrderExtend.getServiceType()),
                        ZhimiConsts.getServiceTypeName(serviceType));
                orderLogDTO.setOperatorLogRemark(errorTip);

                saveOrderLog(orderId, orderLogDTO);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }
        return ResultDTO.success();
    }

    /**
     * 更新智米的故障项字典数据
     * @return
     */
    public ResultDTO refreshZhimiFaults() {
        ApiInvokResult<ZhimiFaultResp> result = ZhimiApiInvoker.queryFaults(null);
        if (!result.isSuccess()) {
            log.info("【{}】更新智米故障基础数据失败：{}。", ZhimiConsts.CHANNEL_NAME, result.getMsg());
            return ResultDTO.fail(result.getMsg());
        }

        ZhimiFaultResp data = result.getData();
        if (data == null || data.getLines() == null) {
            return ResultDTO.fail("未获取到故障数据。");
        }

        List<ChannelZhimiFault> faults = data.getLines().stream().map(item -> {
            ChannelZhimiFault fault = new ChannelZhimiFault();
            fault.setFaultCodeLv3(trim(item.getTertiaryfaultcode()));
            fault.setFaultNameLv3(trim(item.getTertiaryfaultname()));
            fault.setFaultCodeLv2(trim(item.getSecondaryfaultcode()));
            fault.setFaultNameLv2(trim(item.getSecondaryfaultname()));
            fault.setProductCode(trim(item.getTertiaryproductcode()));
            fault.setProductName(trim(item.getTertiaryproductname()));
            return fault;
        }).collect(Collectors.toList());

        channelZhimiFaultService.saveList(faults);

        return ResultDTO.success(String.format("更新成功, 共%d条数据", faults.size()));
    }

    /**
     * 更新智米的配件字典数据
     * @return
     */
    public ResultDTO refreshZhimiFaultParts() {
        ApiInvokResult<ZhimiFaultPartResp> result = ZhimiApiInvoker.queryFaultParts(null);
        if (!result.isSuccess()) {
            log.info("【{}】更新智米故障配件基础数据失败：{}。", ZhimiConsts.CHANNEL_NAME, result.getMsg());
            return ResultDTO.fail(result.getMsg());
        }

        ZhimiFaultPartResp data = result.getData();
        if (data == null || data.getLines() == null) {
            return ResultDTO.fail("未获取到故障配件数据。");
        }

        List<ChannelZhimiFaultPart> parts = data.getLines().stream().map(item -> {
            ChannelZhimiFaultPart part = new ChannelZhimiFaultPart();
            part.setFaultCodeLv3(trim(item.getTertiaryfaultcode()));
            part.setFaultNameLv3(trim(item.getTertiaryfaultname()));
            part.setProductCode(trim(item.getTertiarymodelcode()));
            part.setProductName(trim(item.getTertiarymodelname()));
            part.setPartCode(trim(item.getProductcode()));
            part.setPartName(trim(item.getProductname()));
            part.setRepairCode(trim(item.getRepaircode()));
            part.setRepairName(trim(item.getRepairname()));

            if (StringUtil.isNotBlank(item.getIsuse())) {
                Integer isUse = Integer.parseInt(item.getIsuse().trim());
                part.setIsUse(isUse);
            }

            return part;
        }).collect(Collectors.toList());

        channelZhimiFaultPartService.saveList(parts);

        return ResultDTO.success(String.format("更新成功, 共%d条数据", parts.size()));
    }

    /**
     * 查询ZhimiOrderExtend信息
     * @param orderId
     * @param containsExtendData 返回对象中是否需要包含extendData属性的值
     * @return
     */
    @Override
    public ZhimiOrderExtend findZhimiOrderExtend(Long orderId, boolean containsExtendData) {
        ZhimiExtendOrder model = zhimiExtendOrderService.findByOrderId(orderId, containsExtendData);
        if (model == null) {
            return null;
        }

        return convert2OrderExtend(model);
    }

    /**
     * 检查智米订单数据是否完整，能都操作完成
     * @return
     */
    public ResultDTO check4Complete(Long orderId) {
        ResultDTO resultDTO = null;
        boolean syncExecuted = false;

        do {
            // 给智米同步完成状态
            ZhimiOrderNotifyService notifyService = zhimiOrderNotifyService;
            if (notifyService == null) {
                notifyService = SpringBeanFactoryUtil.getBean("zhimiOrderNotifyService");
                if (notifyService == null) {
                    resultDTO = ResultDTO.fail("系统错误，请稍后再试");
                    break;
                }
                zhimiOrderNotifyService = notifyService;
            }

            if (notifyService.isSyncCompleted(orderId)) {
                resultDTO = ResultDTO.success("无需重复同步完成状态。");
                break;
            }

            OrderExtend orderExtend = orderExtendService.findMiniOrderExtendByOrderId(orderId);
            if (orderExtend != null && StringUtil.isBlank(orderExtend.getImageSrc())) {
                resultDTO = ResultDTO.fail("缺少拍照信息");
                break;
            }

            ZhimiOrderExtend zhimiOrderExtend = findZhimiOrderExtend(orderId, true);
            if (zhimiOrderExtend == null) {
                resultDTO = ResultDTO.fail("订单不存在");
                break;
            }
            Integer serviceType = zhimiOrderExtend.getServiceType();
            // 维修
            if (Objects.equals(serviceType, ZhimiConsts.SERVICE_TYPE_REPAIR)) {
                if (StringUtil.isBlank(zhimiOrderExtend.getSn()) || zhimiOrderExtend.getFaults() == null) {
                    resultDTO = ResultDTO.fail("维修信息不全，请前往智米资料进行填写");
                    break;
                }
                if (StringUtil.isBlank(zhimiOrderExtend.getBuyDate())) {
                    resultDTO = ResultDTO.fail("缺少购机时间信息，请前往智米资料进行填写");
                    break;
                }
                Integer useParts = Optional
                        .ofNullable(zhimiOrderExtend.getUseParts())
                        .orElse(useParts(zhimiOrderExtend.getFaults(), zhimiOrderExtend.getThirdModelCode()));
                if (Objects.equals(ZhimiConsts.YES, useParts)) {
                    if (zhimiOrderExtend.getReturnFactoryExpress() == null) {
                        resultDTO = ResultDTO.fail("缺少旧件返厂信息，请前往智米资料进行填写");
                        break;
                    }
                    // 以换代修订单，必须填写新备件SN码
                    if (Objects.equals(zhimiOrderExtend.getReplaceOnly(), GlobalConsts.YES)
                            && StringUtil.isBlank(zhimiOrderExtend.getNewSn())) {
                        resultDTO = ResultDTO.fail("缺少新机SN码，请前往智米资料进行填写");
                        break;
                    }
                }
            }
            // 退机
            else if (Objects.equals(serviceType, ZhimiConsts.SERVICE_TYPE_RETUND)) {
                if (StringUtil.isBlank(zhimiOrderExtend.getSn()) || zhimiOrderExtend.getFaults() == null) {
                    resultDTO = ResultDTO.fail("退机信息不全，请前往智米资料进行填写");
                    break;
                }
                if (zhimiOrderExtend.getRetund() == null) {
                    resultDTO = ResultDTO.fail("缺少退机类型，请前往智米资料进行填写");
                    break;
                }
                if (StringUtil.isBlank(zhimiOrderExtend.getBuyDate())) {
                    resultDTO = ResultDTO.fail("缺少购机时间信息，请前往智米资料进行填写");
                    break;
                }
                if (!Objects.equals(ZhimiConsts.NO, zhimiOrderExtend.getRetund().getType())
                        && zhimiOrderExtend.getReturnFactoryExpress() == null) {
                    resultDTO = ResultDTO.fail("缺少旧件返厂信息，请前往智米资料进行填写");
                    break;
                }
            }
            // 换机
            else if (Objects.equals(serviceType, ZhimiConsts.SERVICE_TYPE_EXCHANGE)) {
                if (StringUtil.isBlank(zhimiOrderExtend.getSn()) || zhimiOrderExtend.getExchange() == null) {
                    resultDTO = ResultDTO.fail("换机信息不全，请前往智米资料进行填写");
                    break;
                }
                // 不予换机，不用校验后边的数据
                if (!Objects.equals(ZhimiConsts.NO, zhimiOrderExtend.getExchange().getType())) {
                    if (StringUtil.isBlank(zhimiOrderExtend.getNewSn())) {
                        resultDTO = ResultDTO.fail("缺少新机SN码，请前往智米资料进行填写");
                        break;
                    }
                    if (StringUtil.isBlank(zhimiOrderExtend.getBuyDate())) {
                        resultDTO = ResultDTO.fail("缺少购机时间信息，请前往智米资料进行填写");
                        break;
                    }
                    if (zhimiOrderExtend.getReturnFactoryExpress() == null) {
                        resultDTO = ResultDTO.fail("缺少旧件返厂信息，请前往智米资料进行填写");
                        break;
                    }
                }
            }
            // 检测
            else if (Objects.equals(serviceType, ZhimiConsts.SERVICE_TYPE_DETECTION)) {
                if (StringUtil.isBlank(zhimiOrderExtend.getSn()) || zhimiOrderExtend.getDetection() == null) {
                    resultDTO = ResultDTO.fail("检测信息不全，请前往智米资料进行填写");
                    break;
                }
                if (StringUtil.isBlank(zhimiOrderExtend.getBuyDate())) {
                    resultDTO = ResultDTO.fail("缺少购机时间信息，请前往智米资料进行填写");
                    break;
                }
            }
            // 安装
            else if (Objects.equals(serviceType, ZhimiConsts.SERVICE_TYPE_INSTALL)) {
                if (StringUtil.isBlank(zhimiOrderExtend.getSn())) {
                    resultDTO = ResultDTO.fail("安装信息不全，请前往智米资料进行填写");
                    break;
                }
                if (StringUtil.isBlank(zhimiOrderExtend.getBuyDate())) {
                    resultDTO = ResultDTO.fail("缺少购机时间信息，请前往智米资料进行填写");
                    break;
                }
            }
            // 勘测
            else if (Objects.equals(serviceType, ZhimiConsts.SERVICE_TYPE_SURVEY)) {
                if (zhimiOrderExtend.getSurvey() == null) {
                    resultDTO = ResultDTO.fail("勘测信息不全，请前往智米资料进行填写");
                    break;
                }
            }

            // 给智米同步完成状态
            ApiInvokResult apiInvokResult = notifyService.notifyOrderComplete(orderId);
            syncExecuted = true;
            boolean hasMsg = apiInvokResult.getMsg() != null;

            if (!apiInvokResult.isSuccess()) {
                if (hasMsg) {
                    apiInvokResult.setMsg(apiInvokResult.getMsg().replace("，请前往智米资料进行填写", "；"));
                }
                resultDTO = ResultDTO.fail(String.format(
                        "同步智米完成异常，请核实智米资料填写是否准确或者联系言而有信运营，异常原因如下 “%s”",
                        apiInvokResult.getMsg()
                ));
                break;
            }

            // 同步完成成功
            resultDTO = ResultDTO.success(null, hasMsg ? apiInvokResult.getMsg() : "操作完成");
        } while (false);

        // 记录日志
        if (syncExecuted) {
            try {
                OrderLogDTO orderLogDTO = new OrderLogDTO();
                orderLogDTO.setOrderId(orderId);
                orderLogDTO.setWorkId(orderId);

                if (resultDTO.isStatusBool()) {
                    orderLogDTO.setOperatorLogRemark("同步订单完成状态："+ resultDTO.getMessage());
                }
                else {
                    orderLogDTO.setOperatorLogRemark("操作订单完成失败："+ resultDTO.getMessage());
                }

                saveOrderLog(orderId, orderLogDTO);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }

        return resultDTO;
    }

    /**
     * 查询指定时间录入的订单信息
     * @param startTime
     * @param endTime
     * @return
     */
    @Override
    public List<ZhimiOrderExtend> listOrdersByCreateTime(Date startTime, Date endTime) {
        List<ZhimiOrderExtend> list = new LinkedList<>();

        List<ZhimiExtendOrder> zhimiExtendOrders = zhimiExtendOrderService.listByCreateTime(startTime, endTime);
        if (zhimiExtendOrders != null && zhimiExtendOrders.size() > 0) {
            for (ZhimiExtendOrder item : zhimiExtendOrders) {
                list.add(convert2OrderExtend(item));
            }
        }

        return list;
    }

    /**
     * 获取已申请的配件但还没有邮寄信息的订单
     * @return
     */
    @Override
    public List<ZhimiOrderExtend> listNoExpressOrders(Date startTime) {

        List<ZhimiExtendOrder> zhimiExtendOrders = zhimiExtendOrderService.listNoExpressOrders(startTime);
        if (zhimiExtendOrders != null && zhimiExtendOrders.size() > 0) {
            List<ZhimiOrderExtend> collect = zhimiExtendOrders.stream()
                    .map(this :: convert2OrderExtend)
                    .collect(Collectors.toList());
            return collect;
        }

        return null;
    }

    /* ==================================================== */
    /* =================== Private Method ================= */
    /* ==================================================== */
    /**
     * 修改SN码检查结果信息
     * @param orderId
     * @param SNCheckResp   旧机SN校验结果
     * @return ZhimiExtendOrder
     */
    private ZhimiExtendOrder updateSNCheckInfo(Long orderId, ZhimiSNCheckResp SNCheckResp) {
        ZhimiExtendOrder model = new ZhimiExtendOrder();
        model.setOrderId(orderId);
        model.setSn(SNCheckResp.getSn());

        // 三级机型ID
        if (StringUtil.isNotBlank(SNCheckResp.getThirdmodel())) {
            model.setThirdModelCode(SNCheckResp.getThirdmodel());

            ZhimiConsts.MainPartCode mainPartCode = ZhimiConsts.getMainPartCode(model.getThirdModelCode());
            if (mainPartCode != null) {
                // 补充产品名称、整机物料编码 和 机头物料编码
                model.setProductName(mainPartCode.getProductName());
                model.setMainPartCode(mainPartCode.getMainCode());
                model.setHeadPartCode(mainPartCode.getHeadCode());
            }
        }
        // 保修起止时间
        model.setWarrantyBeginTime(SNCheckResp.getBegintime());
        model.setWarrantyEndTime(SNCheckResp.getEndtime());
        // 清除故障信息
        ZhimiOrderExtend dbZhimiOrderExtend = findZhimiOrderExtend(orderId, true);
        dbZhimiOrderExtend.setFaults(null);
        model.setExtendData(convertExtendData2Json(dbZhimiOrderExtend));

        zhimiExtendOrderService.updateByKey(model);

        // 记录日志
        try {
            OrderLogDTO orderLogDTO = new OrderLogDTO();
            orderLogDTO.setOrderId(orderId);
            orderLogDTO.setWorkId(orderId);

            StringBuilder operatorLog = new StringBuilder();
            operatorLog.append("校验SN：").append(SNCheckResp.getSn());

            if (StringUtil.isNotBlank(SNCheckResp.getBegintime())
                    && StringUtil.isNotBlank(SNCheckResp.getEndtime())) {
                operatorLog.append("，保修时间：").append(SNCheckResp.getBegintime())
                        .append(" ~ ").append(SNCheckResp.getEndtime());
            }
            if (StringUtil.isNotBlank(SNCheckResp.getThirdmodel())) {
                operatorLog.append("，三级机型ID：").append(SNCheckResp.getThirdmodel());
            }
            if (StringUtil.isNotBlank(dbZhimiOrderExtend.getSn())) {
                operatorLog.append("，修改SN：[")
                        .append(dbZhimiOrderExtend.getSn())
                        .append("] -> [")
                        .append(SNCheckResp.getSn())
                        .append("]，清空当前购机时间和故障信息");
            }
            operatorLog.append("；");
            orderLogDTO.setOperatorLogRemark(operatorLog.toString());

            saveOrderLog(orderId, orderLogDTO);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        return model;
    }

    /**
     * 修改SN码检查结果信息
     * @param dbZhimiOrderExtend  数据库已存的智米订单信息
     * @param newSNCheckResp 新机SN校验结果
     */
    private void updateNewSNCheckInfo(ZhimiOrderExtend dbZhimiOrderExtend, ZhimiSNCheckResp newSNCheckResp) {
        Long orderId = dbZhimiOrderExtend.getOrderId();
        String newSn = newSNCheckResp.getSn();

        ZhimiExtendOrder model = new ZhimiExtendOrder();
        model.setOrderId(orderId);
        model.setNewSn(newSn);

        zhimiExtendOrderService.updateByKey(model);

        // 记录日志
        try {
            OrderLogDTO orderLogDTO = new OrderLogDTO();
            orderLogDTO.setOrderId(orderId);
            orderLogDTO.setWorkId(orderId);

            String logRemark = String.format("校验新SN：%s；", newSn);
            orderLogDTO.setOperatorLogRemark(logRemark);

            saveOrderLog(orderId, orderLogDTO);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    /**
     * 修改智米扩展数据
     * @param zhimiOrderExtend
     */
    private void updateExtendData(ZhimiOrderExtend zhimiOrderExtend) {
        Long orderId = zhimiOrderExtend.getOrderId();

        ZhimiExtendOrder model = new ZhimiExtendOrder();
        model.setOrderId(zhimiOrderExtend.getOrderId());
        model.setExpressWaiting(zhimiOrderExtend.getExpressWaiting());

        {
            ZhimiOrderExtend extendDataModel = new ZhimiOrderExtend();
            ZhimiOrderExtend dbOrderExtend = findZhimiOrderExtend(orderId, true);

            // 故障
            extendDataModel.setFaults(Optional.ofNullable(zhimiOrderExtend.getFaults())
                    .orElse(dbOrderExtend.getFaults()));
            // 是否使用配件
            extendDataModel.setUseParts(zhimiOrderExtend.getUseParts());
            // 故障
            extendDataModel.setParts(Optional.ofNullable(zhimiOrderExtend.getParts())
                    .orElse(dbOrderExtend.getParts()));
            // 检测结果
            extendDataModel.setDetection(Optional.ofNullable(zhimiOrderExtend.getDetection())
                    .orElse(dbOrderExtend.getDetection()));
            // 勘测结果
            extendDataModel.setSurvey(Optional.ofNullable(zhimiOrderExtend.getSurvey())
                    .orElse(dbOrderExtend.getSurvey()));
            // 换机类型
            extendDataModel.setExchange(Optional.ofNullable(zhimiOrderExtend.getExchange())
                    .orElse(dbOrderExtend.getExchange()));
            // 退货类型
            extendDataModel.setRetund(Optional.ofNullable(zhimiOrderExtend.getRetund())
                    .orElse(dbOrderExtend.getRetund()));
            // 收货地址信息
            extendDataModel.setPostAddress(Optional.ofNullable(zhimiOrderExtend.getPostAddress())
                    .orElse(dbOrderExtend.getPostAddress()));
            // 旧件返厂物流信息
            extendDataModel.setReturnFactoryExpress(Optional.ofNullable(zhimiOrderExtend.getReturnFactoryExpress())
                    .orElse(dbOrderExtend.getReturnFactoryExpress()));

            model.setExtendData(convertExtendData2Json(extendDataModel));
        }

        if (StringUtil.isNotBlank(model.getExtendData())) {
            zhimiExtendOrderService.updateByKey(model);
        }
    }

    /**
     * 补充产品是否在保信息
     * @param updateModel
     * @param dbZhimiOrderExtend
     * @param operatorLog
     */
    private void fillWarrantyInfo(ZhimiExtendOrder updateModel, ZhimiOrderExtend dbZhimiOrderExtend,
                                  StringBuilder operatorLog) {

        Date orderTime = dbZhimiOrderExtend.getCreateTime();    // 下单时间
        Date buyDate = DateUtil.parse(updateModel.getBuyDate(), DateUtil.FORMAT_DATE);

        // 默认在保修期内
        Integer isWarranty = ZhimiConsts.WARRANTY_IN;

        // 使用购机时间，判断是否在保，忽略SN校验返回时间
        Date endTime = DateUtil.addMonth(buyDate, 12 * 3); // 三年质保
        if (endTime.getTime() < orderTime.getTime()) {
            isWarranty = ZhimiConsts.WARRANTY_OUT;
        }
        updateModel.setWarranty(isWarranty);

        // 判断是否优先使用以换代修
        String replaceOnlyLog = null;
        do {
            // 非维修单，默认以换代修（不提供机头以外的配件选择项）
            if (!Objects.equals(ZhimiConsts.SERVICE_TYPE_REPAIR, dbZhimiOrderExtend.getServiceType())) {
                updateModel.setReplaceOnly(GlobalConsts.YES);
                replaceOnlyLog = "非维修单-不提供机头以外的配件选择项";
                break;
            }

            // 保外单，不适用以换代修
            if (Objects.equals(ZhimiConsts.WARRANTY_OUT, updateModel.getWarranty())) {
                updateModel.setReplaceOnly(GlobalConsts.NO);
                replaceOnlyLog = "保外单-不适用以换代修";
                break;
            }

            // 怡和版，一年内使用以换代修，超过一年，不使用以换代修
            ZhimiConsts.MainPartCode mainPartCode =
                    ZhimiConsts.getMainPartCode(dbZhimiOrderExtend.getThirdModelCode());
            if (mainPartCode != null && !mainPartCode.isReplaceOnly()) {
                Date oneYearLaterTime = DateUtil.addMonth(buyDate, 12);
                if (oneYearLaterTime.getTime() > orderTime.getTime()) {
                    updateModel.setReplaceOnly(GlobalConsts.YES);
                    replaceOnlyLog = String.format("保内单-%s-购买不满一年-使用以换代修", mainPartCode.getNickname());
                }
                else {
                    updateModel.setReplaceOnly(GlobalConsts.NO);
                    replaceOnlyLog = String.format("保内单-%s-购买满一年-不适用以换代修", mainPartCode.getNickname());
                }
                break;
            }

            // 保内单：非怡和版/爱创版/西马版，使用以换代修
            updateModel.setReplaceOnly(GlobalConsts.YES);
            replaceOnlyLog = String.format("保内单-%s-使用以换代修",
                    Optional.ofNullable(mainPartCode)
                    .map(e -> e.getNickname())
                    .orElse("该机型不支持维修")
            );
        } while (false);

        operatorLog.append("，").append(replaceOnlyLog);
    }

    /**
     * 添加日志
     *
     * @param orderId
     * @param orderLogDTO
     */
    private void saveOrderLog(Long orderId, OrderLogDTO orderLogDTO) {
        if (orderLogDTO.getType() == null) {
            orderLogDTO.setType(OrderLogConsts.ORDER_LOG_TYPE_CHANNEL_REMARK);
        }
        if (orderLogDTO.getOperatorType() == null) {
            orderLogDTO.setOperatorType(GlobalConsts.OPERATE_USER_TYPE_CHANNEL);
            orderLogDTO.setOperator("渠道");
            orderLogDTO.setOperatorId((long)ZhimiConsts.CHANNEL_ID);
        }

        OrderWork orderWork = orderWorkService.findOrderWorkByKey(orderId, orderId);

        OrderLog orderLog = new OrderLog();
        orderLog.setOrderId(orderId);
        orderLog.setWorkId(orderId);
        orderLog.setType(orderLogDTO.getType());
        orderLog.setTypeName(OrderLogConsts.getOrderLogTypeName(orderLogDTO.getType()));
        orderLog.setBeforeStatus(orderWork.getStatus());
        orderLog.setBeforeStatusName(OrderStatusConsts.getWorkStatusName(orderWork.getStatus()));
        orderLog.setBeforeResultStatus(orderWork.getResultStatus());
        orderLog.setBeforeResultStatusName(OrderStatusConsts.getWorkResultStatusName(orderWork.getResultStatus()));
        orderLog.setAfterStatus(orderWork.getStatus());
        orderLog.setAfterStatusName(OrderStatusConsts.getWorkStatusName(orderWork.getStatus()));
        orderLog.setAfterResultStatus(orderWork.getResultStatus());
        orderLog.setAfterResultStatusName(OrderStatusConsts.getWorkResultStatusName(orderWork.getResultStatus()));
        OrderWorkLogUtils.processOrderLogOperater(orderLog, orderLogDTO);

        StringBuilder sb = new StringBuilder();

        if (StringUtil.isNotBlank(orderLogDTO.getOperatorRemark())) {
            sb.append(orderLogDTO.getOperatorRemark());
        }

        if (StringUtil.isNotBlank(orderLogDTO.getOperatorLogRemark())) {
            sb.append(orderLogDTO.getOperatorLogRemark());
        }

        orderLog.setContent(sb.toString());
        orderLogBService.save(orderLog);
    }

    /**
     * 将 ZhimiOrderExtend 对象中的 ExtendData 数据转换成数据库中存储的json数据格式
     * @param zhimiOrderExtend
     * @return
     */
    private String convertExtendData2Json(ZhimiOrderExtend zhimiOrderExtend) {
        Map<String, Object> dataMap = new HashMap<>();

        List<ZhimiOrderExtend.Fault> faults = zhimiOrderExtend.getFaults();
        if (!CollectionUtils.isEmpty(faults)) {
            dataMap.put("faults", faults);
        }
        Integer useParts = zhimiOrderExtend.getUseParts();
        if (useParts != null) {
            dataMap.put("useParts", useParts);
        }
        List<ZhimiOrderExtend.Part> parts = zhimiOrderExtend.getParts();
        if (!CollectionUtils.isEmpty(parts)) {
            dataMap.put("parts", parts);
        }
        ZhimiOrderExtend.Detection detection = zhimiOrderExtend.getDetection();
        if (detection != null) {
            dataMap.put("detection", detection);
        }
        ZhimiOrderExtend.Survey survey = zhimiOrderExtend.getSurvey();
        if (survey != null) {
            dataMap.put("survey", survey);
        }
        ZhimiOrderExtend.Exchange exchange = zhimiOrderExtend.getExchange();
        if (exchange != null) {
            dataMap.put("exchange", exchange);
        }
        ZhimiOrderExtend.Retund retund = zhimiOrderExtend.getRetund();
        if (retund != null) {
            dataMap.put("retund", retund);
        }
        ZhimiOrderExtend.PostAddress postAddress = zhimiOrderExtend.getPostAddress();
        if (postAddress != null) {
            dataMap.put("postAddress", postAddress);
        }
        ZhimiOrderExtend.ReturnFactoryExpress returnFactoryExpress = zhimiOrderExtend.getReturnFactoryExpress();
        if (returnFactoryExpress != null) {
            dataMap.put("returnFactoryExpress", returnFactoryExpress);
        }

        return dataMap.isEmpty() ? null : JSON.toJSONString(dataMap);
    }

    /**
     * 将数据库中查出的数据转换成 ZhimiOrderExtend 对象
     * @param model
     * @return
     */
    private ZhimiOrderExtend convert2OrderExtend(ZhimiExtendOrder model) {
        ZhimiOrderExtend zhimiOrderExtend = new ZhimiOrderExtend();

        zhimiOrderExtend.setOrderId(model.getOrderId());
        zhimiOrderExtend.setOuterId(model.getOuterId());
        zhimiOrderExtend.setServiceType(model.getServiceType());
        zhimiOrderExtend.setReplaceOnly(model.getReplaceOnly());
        zhimiOrderExtend.setMainPartCode(model.getMainPartCode());
        zhimiOrderExtend.setHeadPartCode(model.getHeadPartCode());
        zhimiOrderExtend.setAcFlag(model.getAcFlag());
        zhimiOrderExtend.setCreateTime(model.getCreateTime());

        zhimiOrderExtend.setSn(model.getSn());
        zhimiOrderExtend.setNewSn(model.getNewSn());
        zhimiOrderExtend.setBuyDate(model.getBuyDate());
        zhimiOrderExtend.setWarranty(model.getWarranty());
        zhimiOrderExtend.setWarrantyBeginTime(model.getWarrantyBeginTime());
        zhimiOrderExtend.setWarrantyEndTime(model.getWarrantyEndTime());
        zhimiOrderExtend.setProductCode(model.getProductCode());
        zhimiOrderExtend.setProductName(model.getProductName());
        zhimiOrderExtend.setThirdModelCode(model.getThirdModelCode());

        String extendDataJson = model.getExtendData();
        if (StringUtil.isNotBlank(extendDataJson)) {
            JSONObject jsonObj = JSON.parseObject(extendDataJson);

            if (jsonObj.containsKey("faults")) {
                List<ZhimiOrderExtend.Fault> faults = jsonObj.getObject("faults",
                        new TypeReference<List<ZhimiOrderExtend.Fault>>() {});
                zhimiOrderExtend.setFaults(faults);
            }
            if (jsonObj.containsKey("useParts")) {
                Integer useParts = jsonObj.getObject("useParts", Integer.class);
                zhimiOrderExtend.setUseParts(useParts);
            }
            if (jsonObj.containsKey("parts")) {
                List<ZhimiOrderExtend.Part> parts = jsonObj.getObject("parts",
                        new TypeReference<List<ZhimiOrderExtend.Part>>() {});
                zhimiOrderExtend.setParts(parts);
            }
            if (jsonObj.containsKey("detection")) {
                ZhimiOrderExtend.Detection detection = jsonObj.getObject("detection", ZhimiOrderExtend.Detection.class);
                zhimiOrderExtend.setDetection(detection);
            }
            if (jsonObj.containsKey("survey")) {
                ZhimiOrderExtend.Survey survey = jsonObj.getObject("survey", ZhimiOrderExtend.Survey.class);
                zhimiOrderExtend.setSurvey(survey);
            }
            if (jsonObj.containsKey("exchange")) {
                ZhimiOrderExtend.Exchange exchange = jsonObj.getObject("exchange", ZhimiOrderExtend.Exchange.class);
                zhimiOrderExtend.setExchange(exchange);
            }
            if (jsonObj.containsKey("retund")) {
                ZhimiOrderExtend.Retund retund = jsonObj.getObject("retund", ZhimiOrderExtend.Retund.class);
                zhimiOrderExtend.setRetund(retund);
            }
            if (jsonObj.containsKey("postAddress")) {
                ZhimiOrderExtend.PostAddress postAddress = jsonObj.getObject("postAddress",
                        ZhimiOrderExtend.PostAddress.class);
                zhimiOrderExtend.setPostAddress(postAddress);
            }
            if (jsonObj.containsKey("returnFactoryExpress")) {
                ZhimiOrderExtend.ReturnFactoryExpress returnFactoryExpress = jsonObj.getObject("returnFactoryExpress",
                        ZhimiOrderExtend.ReturnFactoryExpress.class);
                zhimiOrderExtend.setReturnFactoryExpress(returnFactoryExpress);
            }
        }

        return zhimiOrderExtend;
    }

    private String trim(String str) {
        if (str == null) {
            return str;
        }

        return str.trim();
    }
}
